
\chapter{Sistemas Embarcados}
\label{c:sistemas_embarcados}

No início do uso do computador como um dispositivo produzido em escala moderada,
em torno de 1940 e 1950, as máquinas eram dedicadas a uma única tarefa, mas não
como as conhecemos hoje (PIGUET, 1995). Os computadores eram muito grandes, e
muito caros, para serem utilizados no dia a dia. Desde essa época, a indústria
eletrônica avança e inova constantemente, diminuindo o tamanho dos dispositivos,
mantendo preços de acordo e adicionando sempre novas funcionalidades,
impulsionando o mercado e a pesquisa em novas direções.

No mundo atual, interagimos com dispositivos eletrônicos em todo lugar e a
todo momento: em casa, no escritório, na rua, no carro, em lojas. Comumente,
mesmo sem o conhecimento do homem, o uso de sistemas automatizados abrange todos
os aspectos do cotidiano moderno. A cada momento, é comum dependermos de um ou
mais dispositivos para executar uma certa tarefa. A partir do momento que o uso
de tais aparelhos se torna necessário ou tem um papel importante para, por
exemplo, a segurança de um ser humano, é preciso um planejamento detalhado e
cuidadoso das suas características, que precisam ser bem conhecidas e
especificadas. Tais necessidades fazem com que parte do estudo de sistemas
computacionais seja voltada a esta classe em particular.

Hoje em dia um sistema computacional por si só não apresenta utilidade, porém
ele pode ser inserido em um contexto que o faça útil para o homem, facilitando
a realização de alguma tarefa em particular ou habilitando-o a participar de
novos modos de interação com outros indivíduos. Existe uma disciplina da
Ciência da Computação que estuda este fenômeno, denominada de
\textit{computação pervasiva} ou \textit{computação ubíqua} \cite{comp_ubiqua}.
Os pesquisadores da área acreditam em um futuro \textit{pós-desktop}, onde o ser
humano se depara com dezenas de dispositivos computacionais a todo momento,
todos trabalhando em sincronia, unidos por alguma forma de rede auto adaptativa,
com boas garantias de eficiência e qualidade de serviço. Neste modelo, o
computador tradicional como o conhecemos hoje irá perder lugar para que a sua
funcionalidade seja distribuída entre vários componentes. Entretanto, não é
preciso ser um futurista para observar que o modo como utilizamos um dispositivo
computacional mudou drasticamente já nas últimas décadas. De mainframes
corporativos, capazes de ocupar diversos andares de edifícios, passamos a
utilizar equipamentos cada vez mais diminutos, com poder e eficiência que
ultrapassam os mais antigos por ordens de magnitude. Alguns exemplos disto são
os desktops atuais, notebooks, netbooks e tablets.

\abrv[SE -- Sistema Embarcado]

Ao pensar em ``sistema computacional'', a grande parte das pessoas irá associar
o termo ao computador propriamente dito, seja ele um desktop ou não. O fato é
que esta concepção, herdada historicamente pelo modo como tais sistemas foram
introduzidos na sociedade, é errada. A grande maioria dos sistemas
computacionais em uso hoje em dia não são computadores. \textit{Sistema
Embarcado} (SE) é a denominação dada para um sistema computacional projetado
desde a sua concepção para a realização de um pequeno conjunto de tarefas
simples e bem definidas, para as quais foi programado, possivelmente com
diversas restrições de tempo real \cite{vahid_book}. Em geral, trata-se de um
equipamento que é \textit{embutido} em um dispositivo eletrônico maior, que o
complementa em um sistema de grande porte, servindo para controlar os mais
diversos dispositivos com os quais interagimos.

Existem diversos exemplos de sistemas embarcados projetados para uso doméstico.
Celulares, \emph{smartphones}, consoles de vídeo game, tocadores de MP3, câmeras
de vídeo e/ou fotográficas, impressoras, televisões e ar condicionados são
exemplos de aparelhos projetados para o conforto e entretenimento dos seus
usuários finais. Outros são designados a tarefas mais críticas, tais
como os sistemas de bordo em carros e aviões. Estes envolvem, entre outros,
controle de freios, mistura de combustível, regulação do motor e controle da
transmissão. Um carro popular comum produzido recentemente apresenta dezenas de
dispositivos internos que contém um elemento computacional.

Os sistemas embarcados apresentam, em geral, algumas características em comum,
embora haja diversas exceções à regra. É interessante catalogar estas
características de modo a entender melhor as necessidades destes sistemas.
Abaixo, apresentamos uma caracterização de sistemas embarcados baseada na que
foi apresentada em \cite{vahid_book}:

\begin{itemize}
\item \textbf{Função singular}: Uma única funcionalidade, ou um propósito
único e bem definido. Em geral, isso significa que o dispositivo executa um
único programa indefinidamente, com um pequeno conjunto de funcionalidades de
baixa complexidade. Embora as tarefas que o SE precise realizar sejam simples,
ele, em geral, é composto por um processador capaz de executar software
arbitrariamente complexo, caso haja necessidade. Como veremos a frente,
devido a outros motivos, isto nem sempre é desejável.

\item \textbf{Restrições não-funcionais}: Conjunto de restrições aplicadas a
esses dispositivos devido ao seu contexto de uso, tais como pequeno volume,
baixo consumo elétrico, alta responsividade e baixa latência. Algumas destas
restrições são cruciais para a funcionalidade do dispositivo, enquanto outras
agregam valor do ponto de vista comercial.

\item \textbf{Otimização}: Por ter como propósito poucas tarefas, o sistema
embarcado pode ser otimizado especialmente para a execução delas. Em geral,
isto resulta em um projeto menor e mais conciso, especialmente criado para
que o  dispositivo execute essas tarefas da forma mais eficiente possível.

\item \textbf{Reatividade}: O dispositivo apresenta sensores e uma interface
com o ambiente bem definida, reagindo continuamente a mudanças em variáveis
externas. Exemplos de sistemas embarcados em que a reatividade é uma
característica dominante são sistemas de controle industrial.

\item \textbf{Tempo real}: É comum tais dispositivos estarem embarcados em
ambientes onde os requisitos temporais das suas tarefas sejam críticos. Isto
é, uma tarefa tem o seu sucesso diretamente relacionado com o cumprimento ou
não de certos limites de tempo. Cada sistema tem requisitos distintos, onde
estes limites de tempo (\emph{deadlines}) são mais rígidos ou não.

\item \textbf{Interface básica}: Os primeiros sistemas embarcados eram mais
simples e, em geral, não apresentavam uma interface de interação com o usuário.
Com o avanço das tecnologias utilizadas e da eficiência dos sistemas, os
sistemas foram incorporando esta funcionalidade. Um exemplo deste
processo natural é a recente utilização de telas sensíveis ao toque como
alternativas aos projetos mais tradicionais que utilizavam teclados clássicos.
O uso de tais telas requer hardware mais complexo, e mais custoso, além de
adaptações do software que o controla.
\end{itemize}

A indústria de sistemas embarcados, extremamente diversa, tem um horizonte amplo
de possibilidades no presente e no futuro. Todo dia novos produtos que incluem
sistemas embarcados são projetados e, em um futuro próximo, começam a ser
produzidos. O preço do hardware utilizado nesses dispositivos diminui com o
tempo, com a evolução natural das tecnologias utilizadas, possibilitando que
novas aplicações, antes impossíveis, sejam consideradas. Sistemas embarcados são
utilizados em casa, no trabalho, em automóveis, lugares públicos e hospitais,
com as mais diversas funções. O estudo sistemático desses sistemas, assim
como das técnicas de otimização que lhe podem ser aplicadas, faz-se obviamente
necessário.


\section{Restrições}
\label{s:restricoes}

O projeto de sistemas embarcados está fortemente ligado às tendências atuais da
indústria. Devido ao fato de estarem predominantemente embarcados em outros
dispositivos eletrônicos, estes sistemas estão sujeitos as restrições impostas
pelo projeto de tais dispositivos. Estas restrições podem ser estritamente
técnicas ou não.

Tais restrições podem ser observadas mais praticamente tomando como exemplo um
aparelho celular inteligente (\textit{smartphone}) de última geração, contendo
uma interface de iteração com o usuário baseada em uma tela sensível ao toque
(\textit{touchscreen}). Este sistema pode ser identificado como um sistema
embarcado utilizando a classificação que foi apresentada acima:

\begin{itemize}
\item \textit{Função singular}: Como observado, alguns sistemas não apresentam
esta característica e o celular smartphone moderno é um deles. Este aparelho é
programado para realizar diversas funções desde a saída da fábrica, sendo ainda
extensível através da instalação de programas. Ainda mais, é comum que estes
celulares executem sistemas operacionais de propósito geral. Um kernel Linux
modificado para atender as restrições não-funcionais do aparelho, por exemplo.

\item \textit{Restrições não-funcionais}: O aparelho precisa ser pequeno, com
boas propriedades ergonômicas, assim como consumir pouca energia, de modo a
conservar a sua bateria e aumentar o conforto do usuário. Otimização: Apesar de
executar programas arbitrários, um smartphone é equipado com software e hardware
otimizado para as suas tarefas principais.

\item \textit{Reatividade}: Além de, obviamente, observar as iterações com a
interface com o usuário, o aparelho está constantemente em contato com uma
antena celular próxima, e possivelmente com pontos de acesso para redes Wi-Fi.
Eventos que acontecem nesses pontos de interface com o ambiente externo
determinam o funcionamento do aparelho. 

\item \textit{Tempo-real}: O celular é sujeito a restrições temporais de
intensidade variável de acordo com o estado atual. Por exemplo, é preciso
apresentar uma boa responsividade quando o usuário interage com o menu ou está
executando algum programa interativo (ex: um jogo). Porém, é mais importante
atender os requisitos temporais associados a codificação e decodificação do
áudio em uma ligação telefônica.
\end{itemize}

Estes aspectos introduzem restrições técnicas ao projeto do sistema embarcado
que acompanha um celular smartphone comum. Pode-se citar, por exemplo, o tamanho
do sistema, que deve ser uma das principais preocupações em tempo de projeto.
Isto implica a preferência por componentes de pequena área. Além disso, tais
componentes precisam ter uma eficiência suficiente para que a execução do
software do smartphone seja satisfatória. Isto é, tenha uma boa performance na
iteração com o usuário. Outro aspecto para o conforto geral do usuário final do
produto é uma boa autonomia da sua bateria, uma característica que é
diretamente influenciada pelo hardware utilizado e, de certa maneira, pelo
software também \cite{green_computing}.


\subsection{Influência do mercado}
\label{ss:ip_reuse}

Além das restrições técnicas que são impostas aos sistemas embarcados, existem
também as restrições de mercado. Os produtos em que os sistemas embarcados são
incluídos devem ser projetados de modo a atender satisfatoriamente os
requisitos do usuário final. Nas empresas de ponta, que trabalham com o estado
da arte em suas respectivas áreas e estão sempre liberando produtos inovadores
no mercado, as limitações das tecnologias sendo utilizadas em um dado momento
não influenciam decisivamente o projeto final. Pelo contrário, as necessidades
do usuário final ditam o rumo da inovação tecnológica, e tais empresas
apresentam a necessidade de investir em novas tecnologias.

Estas restrições são capazes de mudar o rumo de um projeto, afetando algumas
decisões mesmo que não haja motivo técnico. São restrições baseadas em
valores de mercado, como lucro, tempo de lançamento do produto no mercado, tempo
de projeto, custo de projeto e custo unitário, entre outros.
\citeonline{vahid_book} mostram que é preciso considerar e otimizar diversas
métricas de projeto de acordo com decisões tanto administrativas quanto
financeiras. Algumas destas métricas são:

\begin{itemize}
\item \textbf{Custo de unidade}: custo da produção de uma unidade do produto,
contando materiais e mão de obra, excluindo custos de projeto. É o custo do
processo de fabricação em si.

\item \textbf{Custo de engenharia}: custo expendido durante todo o projeto do
sistema embarcado, não influenciando o valor do custo de unidade. Inclui, por
exemplo, o capital investido em pesquisa e desenvolvimento do primeiro
protótipo.

\item \textbf{Tempo para o protótipo}: a quantidade de tempo necessária para que
um primeiro protótipo funcional do sistema embarcado seja produzido.

\item \textbf{Tempo para o mercado}: a quantidade de tempo necessária para que a
empresa esteja pronta para a produção do sistema em larga escala, para o
mercado.

\item \textbf{Sucesso do produto}: é uma medida um tanto subjetiva, que pode
ser descrita de maneiras diferentes. Por exemplo, como o lucro da empresa com
este produto, ou o nível de aceitação dele pelo público-alvo.
\end{itemize}

As relações entre estas 5 métricas são bastante subjetivas, e variam de projeto
para projeto. Entretanto algumas correspondências são válidas para a maioria
dos casos. Um maior investimento em pesquisa acarreta um maior tempo para o
protótipo e custo de engenharia, porém tem o potencial de diminuir o custo de
unidade e aumentar o sucesso do produto. 

A otimização destas métricas em termos de minimização ou maximização afeta,
entre outras coisas, a escolha dos componentes de hardware de um sistema
embarcado, assim como a reutilização de código no seu software. O projeto de um
sistema embarcado tradicional apresenta um imenso espaço de decisões. Isto é,
inúmeras escolhas são apresentadas aos projetistas, que devem avaliar suas
vantagens e desvantagens, os compromissos (trade-offs) envolvidos, e decidirem o
caminho a ser escolhido, levando em conta os objetivos da gerência com relação
às métricas apresentadas acima.

\abrv[IP -- Intellectual Property]

Uma tendência clara que pode ser observada, exemplificada em \cite{ip_reuse},
são os esforços empregados na compra e reuso de componentes em forma de
propriedade intelectual (IP, do inglês \emph{intellectual property}) de
terceiros. O uso de componentes pré-projetados, corretos e testados diminui
significantemente o tempo para o protótipo e o tempo para o projeto. De acordo
com o seu preço, o uso de um componente projetado por terceiros tem o potencial
de otimizar também o custo de engenharia e de unidade. Além disso, a facilidade
de incorporação de IP's em um projeto pode ajudar a flexibilizá-lo, agilizando
as mudanças e adaptações do projeto com relação às mudanças constantes de
requisitos no mundo real. Como veremos no capítulo \ref{c:risco}, o
microprocessador de um sistema embarcado é um forte candidato a ser adquirido
via IP.


\section{Software para Sistemas Embarcados}
\label{s:software_embarcado}

\abrv[UCP -- Unidade Central de Processamento]

Para exercitar os diversos tipos de tarefas mencionados anteriormente, os
sistemas embarcados precisam de uma unidade de processamento central (UCP),
semelhante a de um computador pessoal tradicional. As diferenças estão
relacionadas com as restrições explicitadas na seção \ref{s:restricoes},
fazendo com que haja um nicho específico de processadores para sistemas
embarcados.

\abrv[ASIC -- Application-specific integrated circuit]
\abrv[FPGA -- Field-programmable gate array]

Em geral, existem algumas direções distintas para o projeto de uma UCP para um
sistema embarcado: utilizar um microprocessador ``de prateleira'', um
microcontrolador, contendo alguns periféricos em sua placa, um processador
customizado ASIC (do inglês \emph{application-specific integrated circuit}), ou
até um sistema proprietário desenvolvido utilizando a tecnologia FPGA (do
inglês \emph{field-programmable gate array}). Cada opção tem suas vantagens e
desvantagens e vários compromissos (\emph{tradeoffs}) estão envolvidos, assuntos
que fogem do escopo deste trabalho.

O software presente em sistemas embarcados, que será executado por essas
UCP's, apresenta diferenças importantes em relação ao software comum
desenvolvido para dispositivos mais potentes e com menos imposições técnicas. É
interessante notar que as restrições técnicas dos sistemas embarcados afetam
tanto o software produzido como os processos e ferramentas utilizados no seu
desenvolvimento.

\abrv[E/S -- Entrada / Saída]

É possível delinear um esquema básico do processo seguido pelos programadores
deste tipo de software. Primeiramente, é criada uma versão inicial do programa
(protótipo do firmware) do SE, onde a funcionalidade básica está presente,
porém o programa ainda não está totalmente otimizado para as tarefas em questão
e algumas funções que necessitam de uma interface de baixo nível com o hardware
da plataforma do sistema embarcado ainda não estão implementadas. Em iterações
bem definidas, a equipe desenvolve otimizações sob o código original,
possivelmente reescrevendo algumas partes em linguagem de montagem
(\emph{assembly}) para melhorar a performance da aplicação ou introduzir alguma
funcionalidade que necessite de E/S avançado em baixo nível.

Este tipo de cenário onde o programador precisa conhecer detalhes de baixo
nível sobre o hardware do SE é muito comum neste âmbito, embora isto não seja
necessariamente desejável. Ao desenvolver software escrito em linguagem de
montagem, o programador precisa atentar a diversas questões que em outras
situações são totalmente transparentes:

\begin{itemize}
\item \textit{Conjunto de instruções do processador}: estas instruções funcionam
como a ``linguagem de programação'' utilizada e definem toda a semântica do
código em linguagem de montagem. O programador precisa conhecê-las em detalhe,
de modo a poder usufruir da funcionalidade completa que o processador lhe
oferece.

\item \textit{Organização da memória}: qual o tipo da memória, o seu tamanho e
como é dividida. Isto é, detalhes sobre a hierarquia de memória presente na
arquitetura \cite{patterson_book}. Exemplos: detalhes dos segmentos e da
técnica de paginação utilizada, quantidade de níveis de cache e seus tamanhos,
para a arquitetura em questão.

\item \textit{Registradores}: quais os registradores o processador disponibiliza
e quais as suas funções e restrições.

\item \textit{E/S}: quais são as convenções utilizadas para realizar entrada e
saída, tais como memória mapeada e acesso direto. Quais são os passos
necessários para que um programa se comunique com um dispositivo externo, por
exemplo.
\end{itemize}

Tanto para o protótipo como para as suas versões posteriores, é vantajoso
utilizar uma linguagem de programação de  médio nível de abstração, como por
exemplo C, sempre que possível. Tal linguagem permite que o código seja escrito
em uma linguagem com boas abstrações de software, porém com flexibilidade
suficiente para fazer uma interface direta com o hardware caso seja necessário,
utilizando-se de trechos de linguagem de montagem em meio ao código. A equipe
também tem a opção de utilizar um sistema operacional completo, capaz de
simplificar algumas destas tarefas.

Em geral, é um consenso que as linguagens de programação estruturadas são um
avanço importante com relação a linguagens de assembly puro, com vantagens
significativas no contexto dos sistemas embarcados. O uso destas linguagens é
capaz de cortar vários custos do projeto como um todo, seja em tempo de
desenvolvimento ou até em tempo de manutenção do software. A tendência é que,
com a evolução do hardware utilizado nos sistemas embarcados, e a diminuição
dos seus custos, o software desenvolvido seja mais alto nível, de modo a obter
uma maior competitividade nos tempos de lançamento do produto no mercado.
Tradicionalmente, a linguagem C (seguida de perto por C++), junto as linguagens
de montagem das diferentes plataformas, dominam o nicho dos SE's, porém há
esforços para viabilizar a utilização de linguagens de mais alto nível, como
Java \cite{java_embedded_1, java_embedded_2}. Esta tendência é um ponto
importante na argumentação da relevância do trabalho apresentado aqui.

\subsection{Processos de compilação e evolução do software}
\label{ss:compilacao_evolucao}

Para melhor entender os detalhes de como acontece a construção, compilação e
execução de software para sistemas embarcados, iremos apresentar uma visão
geral dos processos e ferramentas envolvidos. 

Um possível ambiente de desenvolvimento de software para SE's, que possibilite
a construção de software que esteja de acordo com os requisitos explicitados
anteriormente, requer uma composição de ferramentas que trabalham em conjunto
para prover esse suporte. Para identificar as ferramentas necessárias,
analisaremos dois fluxogramas tradicionais de desenvolvimento para um sistema
embarcado, em um projeto que utiliza um misto de código em linguagem de alto
nível (neste caso, C) e em linguagem de montagem. O primeiro diz respeito ao
processo de compilação de código, enquanto o segundo exemplifica o processo de
execução, análise, depuração e otimização do programa.

\begin{figure}[htb]
  \centering
  \includegraphics[scale=0.53]{images/fluxograma-desenvolvimento_software}
  \textsf{\caption{Fluxo tradicional de compilação de software misto C e
                   assembly \label{fig:fluxo_desenvolvimento}}}
\end{figure}

A figura \ref{fig:fluxo_desenvolvimento} mostra o modelo tradicional de
compilação de software, uma extensão do fluxograma proposto em
\cite{vahid_book}. Convencionamos neste exemplo em particular que o projeto
apresentado é constituído por 2 códigos-fonte C, \texttt{A.c} e \texttt{B.c}, e
1 arquivo de código fonte assembly, \texttt{C.asm}. O arquivo \texttt{B.c} pode
ser uma biblioteca de código reutilizável com certa funcionalidade requisitada
pelo programa principal, contido em \texttt{A.c}. A unidade \texttt{C.asm} pode
conter implementações em linguagem de montagem do conjunto de funções que
necessitam de acesso direto ao hardware.

A primeira consideração a ser feita é que este processo utiliza a técnica de
\textit{compilação cruzada}. O desenvolvedor cria o código fonte e o compila em
uma máquina host, possivelmente um computador pessoal comum. O arquivo binário
final gerado, entretanto, contêm instruções correspondentes ao processador alvo
do sistema embarcado. Esta é uma abordagem bastante comum. Nestes casos, diz-se
que o compilador é um \textit{compilador cruzado} (do inglês
\textit{cross-compiler}). Esta classificação é somente didática, pois um
compilador cruzado não apresenta diferenças técnicas com relação a um compilador
``normal''.

Seguindo a numeração da figura \ref{fig:fluxo_desenvolvimento}, o processo é
apresentado a seguir. O programador cria, com um editor de texto comum, os
arquivos de código fonte (1). Um compilador C é executado (2), tendo como
entrada os códigos fonte em C. Ele é responsável pela tradução do código
nesta linguagem para uma representação mais próxima do código binário
interpretado pela máquina, a linguagem de montagem. 

Em seguida, o \emph{montador} é executado (3), tendo como entrada os arquivos de
código fonte em linguagem de montagem originais e os gerados pelo compilador.
Ele produz um arquivo em formato de código binário relocável. Neste momento (4),
há um conjunto de arquivos independentes com código binário, cada um
constituindo uma \emph{unidade de compilação} diferente. Além dos arquivos
originais que o programador usou como entrada, ainda são utilizados os códigos
binários da biblioteca padrão da linguagem, além de outras externas que possam
ser utilizadas. Logo após, o \emph{ligador} é executado (5), tendo como entrada
todos os arquivos de código binário. Neste instante, as referências a símbolos
externos presentes em cada unidade de código são resolvidas, e um único arquivo
binário é criado, contendo o executável final. Finalmente, o arquivo executável
final está pronto (6), e pode ser utilizado para execução do programa.

A cada protótipo do sofware que é finalizado, a equipe entra em um ciclo de
teste, análise, depuração e otimização de código, como apresentado na figura
\ref{fig:fluxo_execucao}, baseada nos conceitos em \cite{patterson_book}.

\begin{figure}[htb]
  \centering
  \includegraphics[scale=0.53]{images/fluxograma-execucao_software}
  \textsf{\caption{Fluxo tradicional de execução, depuração e otimização de
                   software \label{fig:fluxo_execucao}}}
\end{figure}

O fluxo de atividades é detalhado a seguir. Primeiramente, a versão atual do
código fonte é compilada (1), através do processo apresentado anteriormente, e o
código binário executável é gerado novamente. Um programa denominado
\textit{carregador} é executado (2), tendo como entrada o arquivo executável.
Este programa é responsável por carregar a imagem estática do programa na
memória do dispositivo, preparando-o para sua execução.

Note que a definição apresentada para o carregador é intencionalmente vaga.
Este poderia ser, por exemplo, um módulo de um sistema operacional de propósito
geral, ou até um programa que transfere o código binário através de uma porta
serial para a memória secundária de um dispositivo eletrônico, como um
micro-controlador.

Em seguida, o programa é executado em um dispositivo (3). Note que o dispositivo
não é necessariamente o sistema embarcado em si. Pode ser um protótipo contendo
somente alguns componentes necessários para a iteração atual, ou um software
simulador da arquitetura do SE. Finalmente, os dados de saída do software (4),
de acordo com as suas respectivas entradas, são utilizados para realizar
correções no código fonte (depuração) ou modificações com o intuito de melhorar
a eficiência do programa (otimização). Em ambos, caso alguma modificação seja
necessária, o processo é reiniciado e o código fonte é recompilado.

As ferramentas apresentadas nesta seção são de caráter básico para o
desenvolvimento de software para SE's. Mostramos no capítulo \ref{c:risco} as
ferramentas que de fato foram implementadas neste trabalho, e como elas se
inserem nos modelos acima.

\subsection{Arquiteturas Comuns}

Basicamente, o software que é executado em um sistema embarcado pode ser
dividido em duas classes \cite{es_architecture_guide}: \emph{software do sistema
básico} e \emph{software de aplicação}. Software do sistema básico é todo código
que tem como fim dar suporte as aplicações que o utilizam. Nesta categoria estão
os drivers de dispositivo, os sistemas operacionais e os \emph{middlewares} de
suporte básico. O software de aplicação compõe a camada superior da pilha de
software de um SE, ele define toda a funcionalidade de alto nível do sistema,
utilizando os serviços das camadas inferiores. É o software que faz a interface
com os usuários do sistema. Ao projetar um sistema embarcado deve-se atentar a
definição detalhada de uma arquitetura de software que equilibre as vantagens e
desvantagens de cada tipo de software. Por exemplo, software do sistema básico é
comumente mais complexo e passível de erros do que o software de aplicação,
porém tem acesso direto ao hardware da plataforma, podendo realizar operações
com maior controle. A partir desta divisão, surgiram diversos padrões de
arquiteturas de software para SE's \cite{es_architecture_guide}. Alguns
significativos são:

\begin{itemize}
  \item \textbf{Loop simples}: Todo o software é software básico. O código é
  simplesmente um loop, chamando rotinas diversas, cada uma gerenciando uma
  parte do hardware. 
  
  \item \textbf{Sistema baseado em interrupções}: Diferentes tarefas são
  acionadas a partir de interrupções recebidas pelo loop principal, cada uma
  realizando uma ação diferente.
  
  \item \textbf{Multiprocessamento cooperativo}: O programador define diversas
  tarefas, cada uma com seu próprio ambiente de execução. Elas cooperam entre
  si para dividir os recursos de hardware.
  
  \item \textbf{Multiprocessamento com preempção}: Geralmente conta com um
  sistema operacional completo como base. O código da aplicação usa o modelo de
  processos distintos, utilizando os serviços do software básico.
\end{itemize}

As ferramentas de desenvolvimento mencionadas em \ref{ss:compilacao_evolucao}
devem ser completas o bastante para suportar o desenvolvimento de software
pertencente a qualquer uma destas arquiteturas.
